import java.util.Arrays;

import constraints.IntConstraint;

/**
 * Determines the outcomes of battles using standard Risk-type rules.
 * 
 * @author Jonathan Caddey
 * @version 2.0
 */
public class BattleMaster {

	public static final IntConstraint ATTACKER_SIZE_CONSTRAINT = new IntConstraint(
			"Attacker army size", 1, 3);
	public static final IntConstraint DEFENDER_SIZE_CONSTRAINT = new IntConstraint(
			"Defender army size", 1, 2);
	private int[] my_attacker_pips;
	private int[] my_defender_pips;
	private int my_attacker_casualties;
	private int my_defender_casualties;
	private final Die my_die;

	public BattleMaster() {
		my_die = new Die();
	}

	/**
	 * 
	 * @requires the_attacker and the_defender be adjacent
	 * @ensures
	 * @param the_attaker
	 * @param the_attacker_num
	 * @param the_defender
	 * @param the_defender_num
	 */
	// TEST COMPLETE? TODO
	// DOC COMPLETE? TODO

	protected void attack(final Territory the_attaker,
			final int the_attacker_num, final Territory the_defender,
			final int the_defender_num) {
		ATTACKER_SIZE_CONSTRAINT.validate(the_attacker_num);
		DEFENDER_SIZE_CONSTRAINT.validate(the_defender_num);

		// TODO check that the countries are adjacent

		// my_attacker_pips overwritten--throw no exceptions beyond this point

		// roll requested attacking die
		my_attacker_pips = new int[the_attacker_num];
		for (int i = 0; i < my_attacker_pips.length; i++) {
			my_die.roll();
			my_attacker_pips[i] = my_die.getPips();
		}

		// roll requested defending die
		final int[] defending_pips = new int[the_defender_num];
		for (int i = 0; i < defending_pips.length; i++) {
			my_die.roll();
			defending_pips[i] = my_die.getPips();
		}

		// pass roll results to helper method
		dieAttack(Arrays.copyOf(my_attacker_pips, my_attacker_pips.length),
				Arrays.copyOf(my_defender_pips, my_defender_pips.length));
	}

	/**
	 * TODO is it allowed for either to be length 0? Pips do not need to be
	 * sorted.
	 * 
	 * It is the responsibility of the caller to pass a copy of the pip arrays
	 * if they should not be sorted.
	 * 
	 * @ensures the_attacker_pips and the_defender_pips will be sorted.
	 * @param the_attacker_pips
	 * @param the_defender_pips
	 */
	// TEST COMPLETE? TODO
	// DOC COMPLETE? TODO
	protected void dieAttack(final int[] the_attacker_pips,
			final int[] the_defender_pips) {
		assert the_attacker_pips != null;
		assert the_defender_pips != null;

		// sort in ascending order so highest pips can be compared
		Arrays.sort(the_attacker_pips);
		Arrays.sort(the_defender_pips);

		my_defender_casualties = 0;
		my_attacker_casualties = 0;

		final int how_many_armies_fight = Math.min(the_attacker_pips.length,
				the_defender_pips.length);
		for (int i = 1; i <= how_many_armies_fight; i++) {
			if (the_attacker_pips[the_attacker_pips.length - i] > the_defender_pips[the_defender_pips.length
					- i]) {
				my_defender_casualties++;
			} else {
				my_attacker_casualties++;
			}
		}
	}

	/**
	 * TODO It may be that this method should return a collection of lost units,
	 * when the game is updated. If that is the case, refactor this method to be
	 * getNumberOfAttackerCasualties and make it protected. This way the unit
	 * tests will still work.
	 * 
	 * @return
	 */
	public int getAttackerCasualties() {
		return my_attacker_casualties;
	}

	/**
	 * TODO It may be that this method should return a collection of lost units,
	 * when the game is updated. If that is the case, refactor this method to be
	 * getNumberOfAttackerCasualties and make it protected. This way the unit
	 * tests will still work.
	 * 
	 * @return
	 */
	public int getDefenderCasualties() {
		return my_defender_casualties;
	}

	public int[] getAttackerPips() {
		return null;
	}

	public int[] getDefenderPips() {
		return null;
	}
	
	// TODO delete this
	public static void main(String args[]) {
		int[] array1 = new int[]{5, 4, 3};
		int[] array2 = Arrays.copyOf(array1, array1.length);
		Arrays.sort(array2);
		System.out.println(Arrays.toString(array1));
		System.out.println(Arrays.toString(array2));
		
	}

}
